/*
 * monitor.cpp
 *
 *  Created on: Sep 11, 2016
 *      Author: ubuntu
 */

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/time.h>
#include <time.h>
#include <fcntl.h>
#include <pthread.h>
#include <libconfig.h++>
#include <vector>
#include <ctype.h>

#include "N900/N900Parse.h"
#include "Conf.h"
#include "common.h"

using namespace std;
using namespace libconfig;

int prodaemon = 1;

struct check_port {
	int port;
	int (*test)(int);
};

static void parse_cmd(int argc, char **argv)
{
	int c;
	while ((c = getopt(argc, argv, "c:d:f")) != -1) {
		switch (c) {
		case 'c':
			if (optarg) {
				SetConf(optarg);
			}
			break;
		case 'd':
			if (optarg) {
				set_debuglevel(atoi(optarg));
			}
			break;
		case 'f':
			prodaemon = 0;
			break;
		default:
			break;
		}
	}
}

int check_n900(int port)
{
	int fd, count = 4;
	while (count--) {
		if ((fd = connect_server("127.0.0.1", port, 10)) > 0)
			break;
	}
	unsigned char buf[30];
	count = 0;
	memset(buf, 0, sizeof(buf));
	memcpy(buf, N900_TAG_HEAD, N900_TAG_HEAD_LEN);
	count += N900_TAG_HEAD_LEN;

	count += 5;
	buf[count++] = 2;
	buf[count++] = 3;
	count++;
	buf[count++] = 3;
	buf[count++] = 1;
	buf[count++] = 1;
	buf[count++] = 5;
	memcpy(buf+count, N900_TAG_TAIL, N900_TAG_TAIL_LEN);
	count += N900_TAG_TAIL_LEN;

	if (write(fd, buf, count) < 0) {
		close(fd);
		return -1;
	}

	bzero(buf, sizeof(buf));
	fd_set rfd;
	FD_ZERO(&rfd);
	FD_SET(fd, &rfd);
	int max = fd;
	struct timeval tv;
	tv.tv_sec = 5;
	tv.tv_usec = 0;
	int res = select(max+1, &rfd, NULL, NULL, &tv);
	if (res <= 0)
		return -1;
	count = read(fd, buf, sizeof(buf));
	close(fd);
	if (count <= 0) {
		return -1;
	}

	return 1;
}

static void 
reset_server()
{
	DIR *dir;
	struct dirent *entry;
	dir = opendir("/proc");
	if (!dir)
		return;
	while ((entry = readdir(dir))) {
		if (strncmp(entry->d_name, ".", 1) == 0)
			continue;

		if (!isdigit(*entry->d_name))
			continue;

		FILE *status;
		char filename[100];
		char buffer[1024];
		char name[100];
		snprintf(filename, sizeof(filename), "/proc/%s/status", entry->d_name);
		if (!(status = fopen(filename, "r")))
			continue;

		if (fgets(buffer, sizeof(buffer), status) == NULL) {
			fclose(status);
			continue;
		}

		fclose(status);

		memset(name, 0, sizeof(name));
		sscanf(buffer, "%*s %s", name);
		if (strstr(name, "CusServer")) {
			memset(filename, 0, sizeof(filename));
			snprintf(filename, sizeof(filename), "kill -9 %s", entry->d_name);
			system(filename);
			break;
		}
	}
	closedir(dir);
}

void *check_server(void *arg)
{
	pthread_mutex_t check_mutex = PTHREAD_MUTEX_INITIALIZER;
	pthread_cond_t check_cond = PTHREAD_COND_INITIALIZER;
	struct timespec timeout;
	vector<struct check_port *> m_lstcheck;

	Config *pConfig = new Config();
	Conf *conf = getConf();
	try {
		pConfig->readFile(conf->path);
		Setting &setting = pConfig->lookup("receiver");
		for (int i = 0; i < setting.getLength(); i++) {
			string type;
			int nPort;
			if (setting[i].lookupValue("type", type)) {
				if (setting[i].lookupValue("port", nPort)) {
					if (type == "N900") {
						struct check_port *port = (struct check_port *)malloc(sizeof(struct check_port));
						port->port = nPort;
						port->test = check_n900;
						m_lstcheck.push_back(port);
					}
				}
			}
		}
	} catch (...) {
		exit(1);
	}
	if (pConfig)
		delete pConfig;

	if (m_lstcheck.empty())
		return NULL;

	bool running = true;
	while (1) {
		timeout.tv_sec = time(NULL) + 300;
		timeout.tv_nsec = 0;

		vector<struct check_port *>::iterator it = m_lstcheck.begin();
		for (; it != m_lstcheck.end(); it++) {
			struct check_port *pCheck = *it;
			if (pCheck->test(pCheck->port) < 0) {
				running = false;
				break;
			}
		}
		if (!running) {
			reset_server();
			running = true;
		}
		pthread_mutex_lock(&check_mutex);

		pthread_cond_timedwait(&check_cond, &check_mutex, &timeout);

		pthread_mutex_unlock(&check_mutex);
	}

	return NULL;
}

void main_loop()
{
	pthread_t tid;
	pthread_create(&tid, NULL, check_server, NULL);
	pthread_detach(tid);
	while (1) {
		system("sh ./cron.sh");
		sleep(30);
	}
}

int main(int argc, char **argv)
{
	/* 初始化系统配置 */
	ConfInit();
	/* 解析命令行 */
	parse_cmd(argc, argv);
	/* 读取配置文件 */
	ReadConf();
	if (prodaemon) {
		if (fork() == 0) {
			main_loop();
		}
	} else {
		main_loop();
	}
	exit(0);
}
